// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "netclientmodel.h"

#include <QDBusReply>
#include <QTimer>

NetClientModel::NetClientModel(QObject *parent)
    : QObject(parent)
    , m_jobThread(nullptr)
    , m_job(nullptr)
    , m_listenerJob(nullptr)
    , m_needSetHttpSrvValidityToAgent(true)
    , m_isHttpSrvValid(false)
    , m_agentDbusIfc(nullptr)
    , m_agentLoginType(IDLE)
    , m_agentLoginState(NONE)
    , m_isInLoginLocalUserInfo(false)
{
    m_jobThread = new QThread();
    m_job = new NetClientJob();
    m_job->moveToThread(m_jobThread);

    m_listenerJob = new NetListenerJob(m_job);
    m_listenerJob->moveToThread(m_jobThread);

    m_agentDbusIfc = new QDBusInterface("com.sgit.agent",
                                        "/com/sgit/agent/http",
                                        "com.sgit.agent.http",
                                        QDBusConnection::systemBus(), this);

    // connect this <=> job
    connect(this, &NetClientModel::requestThreadToRegisterClient, m_job, &NetClientJob::onRequestRegisterClient);
    connect(m_job, &NetClientJob::registerClientFinished, this, &NetClientModel::onRegisterClientFinished);

    connect(this, &NetClientModel::requestThreadToGetQrCode, m_job, &NetClientJob::onRequestGetQrCode);
    connect(m_job, &NetClientJob::getQrCodeFinished, this, &NetClientModel::onGetQrCodeFinished);

    connect(this, &NetClientModel::requestThreadToCheckQrCode, m_job, &NetClientJob::onRequestCheckQrCode);
    connect(m_job, &NetClientJob::checkQrCodeFinished, this, &NetClientModel::onCheckQrCodeFinished);

    connect(this, &NetClientModel::requestThreadToQueryLocalUserInfo, m_job, &NetClientJob::onRequestQueryLocalUserInfo);
    connect(m_job, &NetClientJob::queryLocalUserInfoFinished, this, &NetClientModel::onQueryLocalUserInfoFinished);
    connect(this, &NetClientModel::requestThreadToTryCreateLocalUser, m_job, &NetClientJob::onRequestTryCreateLocalUser);
    connect(this, &NetClientModel::requestThreadToSaveLocalUserInfo, m_job, &NetClientJob::onRequestSaveLocalUserInfo);
    connect(m_job, &NetClientJob::saveLocalUserInfoFinished, this, &NetClientModel::onSaveLocalUserInfoFinished);

    connect(this, &NetClientModel::requestThreadToCheckFace, m_job, &NetClientJob::onRequestCheckFace);
    connect(m_job, &NetClientJob::checkFaceFinished, this, &NetClientModel::onCheckFaceFinished);

    connect(this, &NetClientModel::requestThreadToCheckHttpSrvValidity
            , m_job, &NetClientJob::onRequestCheckHttpSrvValidity);
    connect(m_job, &NetClientJob::checkHttpSrvValidityFinished, this, &NetClientModel::onCheckHttpSrvValidityFinished);

    connect(this, &NetClientModel::requestThreadToStopHttpReply, m_job, &NetClientJob::onRequestStopHttpReply);

    // connect this <=> dbus
    connect(m_agentDbusIfc, SIGNAL(RequestRegisterClient(const QString &)),
            this, SLOT(onRequestRegisterClient(const QString &)));
    connect(m_agentDbusIfc, SIGNAL(Request2DBarcodeImage()),
            this, SLOT(onRequestGetQrCode()));
    connect(m_agentDbusIfc, SIGNAL(Request2DBarcodeVerifyState()),
            this, SLOT(onRequestCheckQrCode()));
    connect(m_agentDbusIfc, SIGNAL(RequestLoginUserInfomation()),
            this, SLOT(onRequestLoginLocalUserInfo()));

    connect(m_agentDbusIfc, SIGNAL(RequestFaceVerify()),
            this, SLOT(onRequestCheckFace()));
    connect(m_agentDbusIfc, SIGNAL(RequestFaceVerifyState()),
            this, SLOT(onRequestSetFaceStateToAgent()));

    connect(m_agentDbusIfc, SIGNAL(NotiyLoginTypeChanged(int)),
            this, SLOT(onNotifyLoginTypeChanged(int)));

    connect(m_agentDbusIfc, SIGNAL(RequestHTTPCheckin()),
            this, SLOT(onRequestCheckHttpSrvValidity()));

    // post init
    m_jobThread->start();
}

NetClientModel::~NetClientModel()
{
    m_job->quit();
    m_jobThread->quit();
    m_jobThread->wait();
    m_jobThread->deleteLater();
    m_jobThread = nullptr;

    m_job->deleteLater();
    m_job = nullptr;
}


void NetClientModel::onRequestRegisterClient(const QString &clientCode)
{
    Q_EMIT requestThreadToStopHttpReply();
    Q_EMIT requestThreadToRegisterClient(clientCode);
}

void NetClientModel::onRequestGetQrCode()
{
    Q_EMIT requestThreadToStopHttpReply();
    Q_EMIT requestThreadToGetQrCode();
}

void NetClientModel::onRequestCheckQrCode()
{
    Q_EMIT requestThreadToCheckQrCode();

    setAgentLoginState(m_agentLoginState);
}

void NetClientModel::onRequestLoginLocalUserInfo()
{
    m_isInLoginLocalUserInfo = true;
    Q_EMIT requestThreadToQueryLocalUserInfo();
}

void NetClientModel::onRequestCheckFace()
{
    m_agentLoginState = AgentLoginState::FACE_WAITTING;
    QDBusReply<QString> reply = m_agentDbusIfc->call("GetFaceData");
    if (!reply.isValid()) {
       qWarning() << Q_FUNC_INFO <<  "GetFaceData failed";
       return;
    }

    const QString &imgData = reply.value();
    Q_EMIT requestThreadToCheckFace(imgData);
}

void NetClientModel::onRequestSetFaceStateToAgent()
{
    setAgentLoginState(m_agentLoginState);
}

void NetClientModel::onNotifyLoginTypeChanged(int type)
{
    m_agentLoginType = AgentLoginType(type);
    m_agentLoginState = AgentLoginState::NONE;

    Q_EMIT requestThreadToStopHttpReply();
}

void NetClientModel::onRequestCheckHttpSrvValidity()
{
    Q_EMIT requestThreadToCheckHttpSrvValidity();
    setHttpSrvValidityToAgent(m_isHttpSrvValid);
}

void NetClientModel::onGetQrCodeFinished(bool successed, const QString &qr)
{
    qInfo() << Q_FUNC_INFO << successed << qr;
    if (AgentLoginType::BARCORD_2D != m_agentLoginType) {
        qWarning() << Q_FUNC_INFO << "current login type is" << m_agentLoginType;
        return;
    }

    if (!successed) {
        qWarning() << Q_FUNC_INFO << "get qr code from server failed";
        return;
    }
    // set qt to agent dbus
    m_agentDbusIfc->call("Set2DBarcodeData", qr);
}

void NetClientModel::onCheckQrCodeFinished(bool successed, NetClientJob::QrStatus status)
{
    qInfo() << Q_FUNC_INFO << status;
    if (AgentLoginType::BARCORD_2D != m_agentLoginType) {
        qWarning() << Q_FUNC_INFO << "current login type is" << m_agentLoginType;
        return;
    }
    if (!successed) {
        qWarning() << Q_FUNC_INFO << "check qr code from server failed";
        return;
    }

    switch (status) {
    case NetClientJob::QrStatus::NotScaned: {
        m_agentLoginState = AgentLoginState::BARCODE_WAITTING;
        break;
    }
    case NetClientJob::QrStatus::ScandedNotAccept: {
        m_agentLoginState = AgentLoginState::BARCODE_SCANNED;
        break;
    }
    case NetClientJob::QrStatus::AcceptLogin: {
        m_agentLoginState = AgentLoginState::BARCODE_SUCCESS;
        break;
    }
    case NetClientJob::QrStatus::AuthFailed: {
        m_agentLoginState = AgentLoginState::BARCODE_FAILED;
        break;
    }
    case NetClientJob::QrStatus::Expired: {
        m_agentLoginState = AgentLoginState::BARCODE_EXPIRED;
        break;
    }
    }
}

void NetClientModel::onQueryLocalUserInfoFinished(bool successed, const QString &localUserName)
{
    qInfo() << Q_FUNC_INFO << localUserName;

    if (!m_isInLoginLocalUserInfo) {
        return;
    }
    if (!successed) {
        qWarning() << Q_FUNC_INFO << "Query Local User Info from server failed";
        Q_EMIT requestThreadToTryCreateLocalUser();
        return;
    }

    m_agentDbusIfc->call("SetLoginLocalUser", localUserName);
    m_isInLoginLocalUserInfo = false;
}

void NetClientModel::onSaveLocalUserInfoFinished(bool successed, const QString &localUserName)
{
    qInfo() << Q_FUNC_INFO << successed << localUserName;
    if (!m_isInLoginLocalUserInfo) {
        return;
    }
    if (!successed) {
        qWarning() << Q_FUNC_INFO << "save Local User Info to server failed";
        return;
    }

    m_agentDbusIfc->call("SetLoginLocalUser", localUserName);
    m_isInLoginLocalUserInfo = false;
}

void NetClientModel::onRegisterClientFinished(bool successed, const QString &clientCode)
{
    qInfo() << Q_FUNC_INFO << successed << clientCode;
    m_agentDbusIfc->call("SetRegisterResult", successed);
}

void NetClientModel::onCheckFaceFinished(bool successed)
{
    if (AgentLoginType::FACE != m_agentLoginType) {
        qWarning() << Q_FUNC_INFO << "current login type is" << m_agentLoginType;
        return;
    }
    qInfo() << Q_FUNC_INFO << successed;
    m_agentLoginState = successed ? AgentLoginState::FACE_SUCCESS : AgentLoginState::FACE_FAILED;
}

void NetClientModel::onCheckHttpSrvValidityFinished(bool valid)
{
    if (!valid) {
        qWarning() << Q_FUNC_INFO << "http server is invalid!";
    }
    m_isHttpSrvValid = valid;
    if (m_needSetHttpSrvValidityToAgent) {
        setHttpSrvValidityToAgent(m_isHttpSrvValid);
        m_needSetHttpSrvValidityToAgent = false;
    }
}

void NetClientModel::setAgentLoginState(AgentLoginState state)
{
    m_agentDbusIfc->call("SetLoginState", state);
}

void NetClientModel::setHttpSrvValidityToAgent(bool valid)
{
    m_agentDbusIfc->call("SetHTTPClientAliveResult", valid);
    m_agentDbusIfc->call("SetHTTPServerAliveResult", valid);
}
